package characters;

import attacks.AttackMethod;

public abstract class GameCharacter {
   /**
    * Character name.
    */
   private String name;
   /**
    * Current life.
    */
   private int life;
   /**
    * Character's attack method.
    */
   private AttackMethod attackMethod;
   /**
    * Level of character.
    */
   private int level;
   /**
    * Guard points (block attacks)
    */
   private int guard;
   
   public GameCharacter(String name, int life, AttackMethod attackMethod, int level, int guard) {
      this.name = name;
      this.attackMethod = attackMethod;
      this.life = life;
      this.level = level;
      this.guard = guard;
   }
   
   /**
    * Attacks the target and also gets attacked back if possible.
    * @param opponent  aim of the attack
    */
   public void attack(GameCharacter opponent) {
      System.out.println(this + " attacks " + opponent);
      dealDamage(opponent);
      
      if (opponent.getLife() > 0) {
         System.out.println(opponent + " counterattacks " + this);
         for (int i = 0; i < opponent.level; i++) {
            opponent.dealDamage(this);
         }
      }
      
      System.out.println();
   }
   
   /**
    * Called out by the attack() method.
    */
   private void dealDamage(GameCharacter target) {
      if (target.getLife() <= 0) {
         System.out.println("target is already dead!");
         return;
      }
      int cuttedGuard = target.getTotalGuard(attackMethod.getCutThrough());
      target.reduceLife(attackMethod.getDamage() - cuttedGuard);
      System.out.print(target + " recieves damage: " + attackMethod.getDamage() + " points of " + attackMethod);
      if (cuttedGuard > 0) {
         System.out.println(". Defended " + cuttedGuard + " points");
      } else {
         System.out.println();
      }
      System.out.println("Remaining: " + target.getLife() + " hp");
   }
   
   /**
    * Returns the total guard after taking into account the cutThrough of an attack method.
    */
   private int getTotalGuard(int cutThrough) {
      int total = guard - cutThrough;
      if (total < 0) {
         return 0;
      }
      return total;
   }

   public int getLife() {
      return life;
   }

   /**
    * Life cannot go under 0<br>
    * 0 = dead.
    */
   public void setLife(int life) {
      if (life < 0) {
         life = 0;
      }
      this.life = life;
   }
   
   public void reduceLife(int change) {
      setLife(getLife() - change);
   }
   
   public void increaseLife(int change) {
      setLife(getLife() + change);
   }

   @Override
   public String toString() {
      String lvlStr = "";
      if (this instanceof Monster) {
         lvlStr = "Level " + level + " ";
      }
      return lvlStr + this.getClass().getSimpleName() + " <<" + name + ">>";
   }   
   
   public String getDescription() {
      return "remaining life:" + life + " | attack method: " + attackMethod;
   }

   public void setAttackMethod(AttackMethod attackMethod) {
      this.attackMethod = attackMethod;
   }
}
